<template>
  <div class="equipment_boxs"></div>
</template>

<script>
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js'

export default {
  props: {
    mxmtnumber: {
      default: 0,
      type: Number
    }
  },
  data() {
    return {
      baseURL: 'https://zfatt.oss-cn-beijing.aliyuncs.com/experiment/zk/',
      loading: true,
      maincontWidth: 0,
      maincontHeight: 0,
      maincontSc: 0,
      camera: null,
      scene: null,
      renderer: null,
      objectReItem: null, // 存储加载的GLB模型实例
      controls: null,
      newcontrols: null,
      clock: null,
      raycaster: null,
      mouse: null,
      cameraOriginal: [1, 0.5, -0.3],
      objects: [],
      gltfLoader: null, // 存储加载器实例（用于销毁）
      dracoLoader: null // 存储DRACO加载器实例（用于销毁）
    }
  },
  mounted() {
    this.init()
    this.destroyThreeJS()
  },
  // 页面销毁时自动触发（Vue生命周期钩子）
  beforeUnmount() {
    this.destroyThreeJS()
  },
  methods: {
    back() {
      this.$emit('back')
    },
    init() {
      this.$nextTick(() => {
        this.maincontWidth = this.$el.offsetWidth
        this.maincontHeight = this.$el.offsetHeight
        this.maincontSc = this.maincontWidth / this.maincontHeight
        this.clock = new THREE.Clock()
        this.mouse = new THREE.Vector2()
        this.raycaster = new THREE.Raycaster()
        this.initScene()
      })
    },
    initScene() {
      this.scene = new THREE.Scene()
      const whiteColor = new THREE.Color(0xffffff)
      this.scene.background = whiteColor

      this.initLight()
      this.initCamera()
      this.initRenderer()
      this.initControl()
      this.animate()
      this.initFile()
    },
    initLight() {
      const ambientLight = new THREE.AmbientLight(0xffffff, 1)
      this.scene.add(ambientLight)
      const directionalLight = new THREE.DirectionalLight(0xffffff, 0.4)
      directionalLight.position.set(5, 5, 5)
      directionalLight.castShadow = true
      directionalLight.shadow.camera.top = 10
      directionalLight.shadow.camera.bottom = 10
      directionalLight.shadow.camera.left = 10
      directionalLight.shadow.camera.right = -10
      this.scene.add(directionalLight)
    },
    initCamera() {
      this.camera = new THREE.PerspectiveCamera(35, this.maincontSc, 0.1, 1000)
      this.camera.position.set(0.9, 1.6, -0.21)
      this.camera.lookAt(0, 0, 0)
      this.scene.add(this.camera)
    },
    initRenderer() {
      this.renderer = new THREE.WebGLRenderer({
        antialias: true,
        logarithmicDepthBuffer: true
      })
      this.renderer.setPixelRatio(window.devicePixelRatio)
      this.renderer.setSize(this.maincontWidth, this.maincontHeight)
      this.renderer.shadowMap.enabled = true
      this.renderer.shadowMap.type = THREE.PCFSoftShadowMap
      this.renderer.toneMapping = THREE.ACESFilmicToneMapping
      this.renderer.toneMappingExposure = 1.5
      this.renderer.outputColorSpace = THREE.SRGBColorSpace
      this.$el.appendChild(this.renderer.domElement)
      window.addEventListener('resize', this.onWindowResize)
    },
    onWindowResize() {
      this.maincontWidth = this.$el.offsetWidth
      this.maincontHeight = this.$el.offsetHeight
      this.maincontSc = this.maincontWidth / this.maincontHeight
      this.camera.aspect = this.maincontSc
      this.camera.updateProjectionMatrix()
      this.renderer.setSize(this.maincontWidth, this.maincontHeight)
    },
    initFile() {
      // 初始化加载器并存储到data（方便后续销毁）
      this.gltfLoader = new GLTFLoader()
      this.dracoLoader = new DRACOLoader()
      this.dracoLoader.setDecoderPath(
        'http://zfatt.oss-cn-beijing.aliyuncs.com/threejs/draco/'
      )
      this.dracoLoader.preload()
      this.gltfLoader.setDRACOLoader(this.dracoLoader)

      const that = this
      this.gltfLoader.load(
        this.baseURL + this.mxmtnumber + '.glb',
        function (glat) {
          that.loading = false
          that.objectReItem = glat.scene // 存储模型实例到data

          that.objectReItem.traverse(function (child) {
            if (child.isMesh) {
              child.castShadow = true
              child.receiveShadow = true
              if ([2, 3, 14, 16, 12].includes(that.mxmtnumber)) {
                child.scale.multiplyScalar(4)
              }
            }
          })

          that.scene.add(that.objectReItem)
          that.objects.push(that.objectReItem) // 加入可交互对象列表
        }
      )
    },
    onDocumentMouseMove(event) {
      event.preventDefault()
      const maincontWidth = this.$el.offsetWidth
      const maincontHeight = this.$el.offsetHeight
      this.mouse.x = (event.offsetX / maincontWidth) * 2 - 1
      this.mouse.y = -(event.offsetY / maincontHeight) * 2 + 1
      this.raycaster.setFromCamera(this.mouse, this.camera)
      const intersections = this.raycaster.intersectObjects(this.objects)
      document.body.style.cursor =
        intersections.length > 0 ? 'pointer' : 'initial'
    },
    onDocumentMouseDown(event) {
      event.preventDefault()
      const maincontWidth = this.$el.offsetWidth
      const maincontHeight = this.$el.offsetHeight
      this.mouse.x = (event.offsetX / maincontWidth) * 2 - 1
      this.mouse.y = -(event.offsetY / maincontHeight) * 2 + 1
      this.raycaster.setFromCamera(this.mouse, this.camera)
    },
    initControl() {
      this.$el.addEventListener('mousemove', this.onDocumentMouseMove, false)
      this.$el.addEventListener('click', this.onDocumentMouseDown, false)
      this.controls = new OrbitControls(this.camera, this.renderer.domElement)
      this.controls.maxDistance = 2
    },
    zx() {
      const offset = new THREE.Vector3(0, 0, 0)
      offset.applyEuler(this.camera.rotation)
      this.controls.target.copy(this.camera.position).sub(offset)
    },
    animate() {
      requestAnimationFrame(this.animate)
      this.renderer.render(this.scene, this.camera)
    },

    // --------------------------
    // 核心：Three.js 资源销毁函数
    // --------------------------
    destroyThreeJS() {
      console.log('Three.js 资源开始销毁')

      // 1. 停止动画循环（避免销毁后仍执行渲染）
      cancelAnimationFrame(this.animate)

      // 2. 销毁 OrbitControls 控制器
      if (this.controls) {
        this.controls.dispose() // 释放控制器资源
        this.controls = null
      }

      // 3. 销毁加载器（GLTFLoader + DRACOLoader）
      if (this.gltfLoader) {
        this.gltfLoader.manager.dispose() // 销毁加载器管理器
        this.gltfLoader = null
      }
      if (this.dracoLoader) {
        this.dracoLoader.dispose() // 释放DRACO解码器资源
        this.dracoLoader = null
      }

      // 4. 递归销毁场景中的所有对象（模型、灯光、几何体、材质等）
      const disposeObject = (obj) => {
        // 销毁几何体
        if (obj.geometry) {
          obj.geometry.dispose()
        }
        // 销毁材质（处理数组/单个材质）
        if (obj.material) {
          if (Array.isArray(obj.material)) {
            obj.material.forEach((mat) => mat.dispose())
          } else {
            obj.material.dispose()
          }
        }
        // 递归销毁子对象
        if (obj.children && obj.children.length > 0) {
          obj.children.forEach((child) => disposeObject(child))
        }
        // 从父场景中移除当前对象
        if (obj.parent) {
          obj.parent.remove(obj)
        }
      }

      // 先销毁加载的GLB模型（单独存储的实例）
      if (this.objectReItem) {
        disposeObject(this.objectReItem)
        this.objectReItem = null
      }

      // 再销毁整个场景的所有对象
      if (this.scene) {
        this.scene.traverse((obj) => disposeObject(obj))
        this.scene = null
      }

      // 5. 销毁相机
      if (this.camera) {
        this.camera = null
      }

      // 6. 销毁渲染器（关键：释放WebGL上下文）
      if (this.renderer) {
        // 移除canvas元素（避免DOM残留）
        const canvas = this.renderer.domElement
        if (canvas && canvas.parentNode) {
          canvas.parentNode.removeChild(canvas)
        }
        this.renderer.dispose() // 释放WebGL上下文和GPU资源
        this.renderer = null
      }

      // 7. 移除所有事件监听（避免内存泄漏）
      window.removeEventListener('resize', this.onWindowResize)
      if (this.$el) {
        this.$el.removeEventListener('mousemove', this.onDocumentMouseMove)
        this.$el.removeEventListener('click', this.onDocumentMouseDown)
      }

      // 8. 清空其他辅助对象
      this.clock = null
      this.raycaster = null
      this.mouse = null
      this.objects = []

      console.log('Three.js 资源销毁完成')
    }
  }
}
</script>

<style>
.equipment_boxs {
  z-index: 9;
  width: 100%;
  height: 100%;
}
</style>
